use crate::context::Context;
use crate::interface::{EventTrigger, Schedule};
use std::collections::VecDeque;
use wd_tools::ptr::force_box_to_var;

pub struct Event<S>
where
    S: Schedule,
{
    schedule: S,
}

impl<S> Event<S>
where
    S: Schedule,
{
    pub fn new(schedule: S) -> Self {
        Self { schedule }
    }
}

impl<S> Event<S>
where
    S: Schedule,
{
    pub async fn launch<T: EventTrigger>(&self, ctx: Context, trigger: T) -> anyhow::Result<T> {
        let type_id = trigger.event_type_id();
        let es = self.schedule.schedule(type_id);
        let deque = VecDeque::from(es);
        ctx.unsafe_store_handle(deque);
        return next(ctx, trigger).await;
    }
}

impl Context {
    pub async fn next<T: EventTrigger>(self, trigger: T) -> anyhow::Result<T> {
        next(self, trigger).await
    }
}

pub async fn next<T: EventTrigger>(ctx: Context, trigger: T) -> anyhow::Result<T> {
    let handle = if let Some(s) = ctx.unsafe_pop_handle() {
        s
    } else {
        return Ok(trigger);
    };
    let res = handle.launch(ctx, Box::new(trigger)).await?;
    Ok(force_box_to_var::<_, T>(res))
}
